package day26.yichang;

/**
 * 异常处理综合示例
 * 演示异常处理的各个方面，包括继承层次、异常链等
 */
public class ComprehensiveExceptionDemo {
    
    /**
     * 演示异常链的处理
     * 异常链允许我们将一个异常包装在另一个异常中，保留原始异常信息
     * 这样可以提供更丰富的错误上下文信息
     * 
     * @throws Exception 抛出包装后的异常
     */
    public static void level1() throws Exception {
        try {
            // 调用level2方法，可能会抛出NumberFormatException
            level2();
        } catch (NumberFormatException e) {
            // 创建新的异常并链接原来的异常
            // 通过构造函数的第二个参数将原始异常作为"原因"传递
            throw new Exception("在level1中处理异常", e);
        }
    }
    
    /**
     * 演示异常类型的转换
     * 将较低级别的IllegalArgumentException转换为较高级别的NumberFormatException
     * 这种做法可以隐藏底层实现细节，提供统一的异常接口
     * 
     * @throws NumberFormatException 抛出数字格式异常
     */
    public static void level2() throws NumberFormatException {
        try {
            // 调用level3方法，可能会抛出IllegalArgumentException
            level3();
        } catch (IllegalArgumentException e) {
            // 将IllegalArgumentException转换为NumberFormatException
            // 这样做可以统一异常类型，便于上层代码处理
            throw new NumberFormatException("数据格式错误");
        }
    }
    
    /**
     * 抛出最底层的异常
     * 直接抛出IllegalArgumentException表示参数不合法
     * 
     * @throws IllegalArgumentException 参数不合法异常
     */
    public static void level3() throws IllegalArgumentException {
        // 直接抛出异常
        throw new IllegalArgumentException("参数不合法");
    }
    
    /**
     * 演示多层catch块的执行顺序
     * Java异常处理遵循"先匹配先执行"原则
     * 子类异常应该放在父类异常之前捕获，否则子类异常将永远不会被捕获
     */
    public static void multipleCatchDemo() {
        try {
            int[] arr = {1, 2, 3};
            // parseInt方法会抛出NumberFormatException（是RuntimeException的子类）
            int index = Integer.parseInt("abc"); // 这里会抛出NumberFormatException
            System.out.println(arr[index]);
        } catch (NumberFormatException e) {
            // NumberFormatException是IllegalArgumentException的子类
            // 会首先被捕获，因为它是更具体的异常类型
            System.out.println("捕获NumberFormatException: " + e.getClass().getSimpleName());
        } catch (RuntimeException e) {
            // 这个catch块不会执行，因为NumberFormatException已经被上面捕获
            // 如果要执行到这里，需要将上面的NumberFormatException catch块移除
            System.out.println("捕获RuntimeException: " + e.getClass().getSimpleName());
        } catch (Exception e) {
            // 这个catch块也不会执行
            // Exception是所有异常的父类，应该放在catch块的最后
            System.out.println("捕获Exception: " + e.getClass().getSimpleName());
        }
    }
    
    /**
     * 演示return语句与finally的执行顺序
     * finally块中的代码总是会执行（除非JVM提前退出）
     * 但return语句的值在进入finally之前就已经确定了
     * 
     * @return 返回整数值10
     */
    public static int returnWithFinally() {
        try {
            // 返回值10在执行finally块之前就已经确定了
            return 10;
        } catch (Exception e) {
            // 这个catch块在本例中不会执行，因为try块中没有异常
            return 20;
        } finally {
            // finally块总是会执行，即使try块中有return语句
            System.out.println("finally块总是会执行");
            // 注意：如果在finally中有return语句，会覆盖try中的return值
            // 这是因为finally中的return会改变方法的退出点
        }
    }
    
    /**
     * 程序主入口
     * 演示各种异常处理机制
     * 
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        System.out.println("=== 异常处理综合示例 ===");
        
        // 演示异常链
        System.out.println("1. 演示异常链:");
        try {
            // 调用level1方法，会引发异常链反应
            level1();
        } catch (Exception e) {
            // 打印异常信息和异常链
            System.out.println("捕获异常: " + e.getMessage());
            // getCause()方法获取异常的原因（即包装的原始异常）
            System.out.println("异常链中的原因: " + e.getCause().getMessage());
            // 获取根本原因（嵌套在最内层的原始异常）
            System.out.println("根本原因: " + e.getCause().getCause().getMessage());
        }
        
        System.out.println("\n2. 演示多层catch块:");
        // 调用演示多层catch块的方法
        multipleCatchDemo();
        
        System.out.println("\n3. 演示return与finally:");
        // 调用演示return与finally执行顺序的方法
        int result = returnWithFinally();
        System.out.println("函数返回值: " + result);
        
        System.out.println("\n4. 演示printStackTrace方法:");
        try {
            // 制造一个NullPointerException异常
            String str = null;
            int len = str.length(); // 会产生NullPointerException
        } catch (NullPointerException e) {
            // printStackTrace方法会将异常的堆栈跟踪信息打印到标准错误流
            // 堆栈跟踪显示了异常发生的完整调用链
            System.out.println("打印异常堆栈跟踪:");
            e.printStackTrace();
        }
        
        System.out.println("\n程序执行完毕");
    }
}